﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Markup;
using SilverTile.Viewports;
using SilverTile.Sprites;
using SilverTile.ExtensionMethods;

namespace SilverTile.Xaml
{

    [ContentProperty("GameAreas")]
    public class SilverTileGameWorld : FrameworkElement, IUpdateable
    {

        public const string PlayerSpriteKey = "Player";

        private List<SpawnPoint> _spawnPoints = new List<SpawnPoint>();
        private Viewports.AreaTransition _previousTransition;

        public SilverTileGameWorld()
        {
            GameAreas = new List<GameAreaGrid>();
        }

        #region Dependency properties
        public static readonly DependencyProperty GameAreasProperty =
            DependencyProperty.Register("GameAreas", typeof(List<GameAreaGrid>), typeof(SilverTileGameWorld), null);
        public List<GameAreaGrid> GameAreas
        {
            get { return (List<GameAreaGrid>)GetValue(GameAreasProperty); }
            set { SetValue(GameAreasProperty, value); }
        }

        public static readonly DependencyProperty StartAreaNameProperty = DependencyProperty.Register("StartAreaName", typeof(string), typeof(SilverTileGameWorld), null);
        public string StartAreaName
        {
            get { return (string)GetValue(StartAreaNameProperty); }
            set { SetValue(StartAreaNameProperty, value); }
        }

        public static readonly DependencyProperty StartColumnProperty = DependencyProperty.Register("StartColumn", typeof(int), typeof(SilverTileGameWorld), null);
        public int StartColumn
        {
            get { return (int)GetValue(StartColumnProperty); }
            set { SetValue(StartColumnProperty, value); }
        }

        public static readonly DependencyProperty StartRowProperty = DependencyProperty.Register("StartRow", typeof(int), typeof(SilverTileGameWorld), null);
        public int StartRow
        {
            get { return (int)GetValue(StartRowProperty); }
            set { SetValue(StartRowProperty, value); }
        }
        #endregion

        public GameAreaGrid GetGameArea(string areaName)
        {
            return GameAreas
                .Where(a => a.AreaName.Equals(areaName))
                .FirstOrDefault();
        }

        public IViewport Viewport { get; internal set; }

        private ISprite _playerSprite;
        public ISprite PlayerSprite
        {
            get { return _playerSprite; }
            set
            {
                _playerSprite = value;
                Viewport.AddSprite(PlayerSpriteKey, _playerSprite);
            }
        }

        public virtual void Update(TimeSpan elapsedTime)
        {

            var transition = GetAreaTransitionAtPlayersLocation();

            if (transition != null && transition != _previousTransition)
            {
                BeginAreaTransition(transition);
            }
            else if (transition == null)
            {
                _previousTransition = null;
            }

            SpawnEnemies(elapsedTime);

        }

        private Viewports.AreaTransition GetAreaTransitionAtPlayersLocation()
        {

            return
                Viewport
                .AreaTransitions
                .Where(t => t.CollisionSides.IsAnySet(t.Sprite.CollidesWithDir(PlayerSprite, t.Sprite.X, t.Sprite.Y, -1)))
                .FirstOrDefault();

        }

        public Action<Viewports.AreaTransition> BeginAreaTransitionAction { get; set; }

        protected virtual void BeginAreaTransition(Viewports.AreaTransition transition)
        {
            if (BeginAreaTransitionAction != null)
            {
                BeginAreaTransitionAction(transition);
            }
            else
            {
                EndAreaTransition(transition);
            }
        }

        public virtual void EndAreaTransition(Viewports.AreaTransition transition)
        {
            PerformAreaTransition(transition);
        }

        protected virtual void PerformAreaTransition(Viewports.AreaTransition transition)
        {

            GameAreaGrid targetArea = GetGameArea(transition.TargetAreaName);
            ActiveArea = targetArea;
            Viewport.SetGameArea(targetArea);

            Viewport
                .ActiveSprites
                .Where(s => s.Key != PlayerSpriteKey)
                .Select(s => s.Key)
                .ToList()
                .ForEach(k => Viewport.RemoveSprite(k));            

            if (AreaTransitionAction != null)
            {
                AreaTransitionAction(this);
            }

            LoadSpawnPoints(targetArea);

            PlayerSprite.X = transition.TargetColumn * targetArea.TileWidth;
            PlayerSprite.Y = transition.TargetRow * targetArea.TileHeight;

            _previousTransition = GetAreaTransitionAtPlayersLocation();

        }

        public void LoadSpawnPoints(GameAreaGrid gameArea)
        {
            _spawnPoints = gameArea
                .BackgroundSprites
                .Where(s => s.SpawnPoint != null)
                .Select(s => s.SpawnPoint)
                .ToList();

            _spawnPoints
                .Where(s => s.SpawnAtStartup)
                .ToList()
                .ForEach(s => Spawned(this, new SpawnedEventArgs(s, s.Tile)));
        }

        private void SpawnEnemies(TimeSpan elapsedTime)
        {

            _spawnPoints.ForEach(s => s.TimeSinceLastSpawn += elapsedTime);

            var possibleSpawnPoints = _spawnPoints.Where(s => s.CanSpawn).ToList();

            possibleSpawnPoints.ForEach(s => s.TimeSinceLastSpawn = TimeSpan.Zero);

            var selectedSpawnPoint = possibleSpawnPoints
                .Where(s => SilverTileGame.Rnd.Percent() < s.SpawnProbability)
                .OrderBy(s => SilverTileGame.Rnd.Next()) // Select a random spawn point
                .FirstOrDefault();

            if (selectedSpawnPoint != null && Spawned != null)
            {

                Spawned(this, new SpawnedEventArgs(selectedSpawnPoint, selectedSpawnPoint.Tile));

                //Type spawnType = Type.GetType(selectedSpawnPoint.SpriteClassName, true);
                
                //ISprite spawnedSprite = Activator.CreateInstance(spawnType, 32, 32) as ISprite;
                //spawnedSprite.X = selectedSpawnPoint.Tile.X * ActiveArea.TileWidth;
                //spawnedSprite.Y = selectedSpawnPoint.Tile.Y * ActiveArea.TileHeight;
                //spawnedSprite.Viewport = Viewport;

                //Viewport.AddSprite(spawnedSprite.GetHashCode().ToString(), spawnedSprite);

            }

            //if (selectedSpawnPoint != null && Spawned != null)
            //{
            //    var eventArgs = new SpawnedEventArgs
            //    {
            //        SpriteType = selectedSpawnPoint.SpriteType,
            //        Tile = selectedSpawnPoint.Tile
            //    };
            //    Spawned(selectedSpawnPoint, eventArgs);
            //}

        }

        public GameAreaGrid ActiveArea { get; set; }
        public Action<SilverTileGameWorld> AreaTransitionAction { get; set; }

        public event EventHandler<SpawnedEventArgs> Spawned;

        public class SpawnedEventArgs : EventArgs
        {
            public SpawnedEventArgs(SpawnPoint spawnPoint, SpriteTile tile)
            {
                SpawnPoint = spawnPoint;
                Tile = tile;
            }

            public SpawnPoint SpawnPoint { get; set; }
            public SpriteTile Tile { get; set; }
        }
    }
}
